﻿using System.Collections.Generic;
using UnityEngine;

public class RoadLength : MonoBehaviour
{
    public MeshFilter meshFilter;
    public Material material;
    void Start()
    {
    }
    public GameObject temp;
    public List<Vector3> l_vertesx;
    #region 创建路径
    Mesh CreateRoad(Vector3[] trans, float width)
    {
        float Materials_Width = width;
        #region vertices
        l_vertesx = new List<Vector3>();

        float uvi = 0;

        List<Vector2> l_uv = new List<Vector2>();
        Vector3[] _abcd = GetABCD(trans[0], trans[1], width / 2);
        l_vertesx.Add(_abcd[0]);
        l_vertesx.Add(_abcd[3]);
        l_uv.Add(new Vector2(0, 0));
        l_uv.Add(new Vector2(0, 1));

        Vector3 lastR = l_vertesx[0];
        Vector3 lastL = l_vertesx[1];

        for (int i = 1; i < trans.Length - 1; i++)
        {
            #region abcd-opmn
            Vector3[] abcd = GetABCD(trans[i - 1], trans[i], width / 2);
            Vector3 a = abcd[0];
            Vector3 b = abcd[1];
            Vector3 c = abcd[2];
            Vector3 d = abcd[3];

            ST(a, P[i], "a");
            ST(b, P[i], "b");
            ST(c, P[i], "c");
            ST(d, P[i], "d");


            Vector3[] opmn = GetABCD(trans[i + 1], trans[i], width / 2);
            Vector3 o = opmn[0];
            Vector3 p = opmn[1];
            Vector3 m = opmn[2];
            Vector3 n = opmn[3];
            
            ST(o, P[i], "o");
            ST(p, P[i], "p");
            ST(m, P[i], "m");
            ST(n, P[i], "n");

            #endregion
            Vector3 cl3 = trans[i] - trans[i - 1];
            Vector3 nc3 = trans[i + 1] - trans[i];
            Vector3 crossRes = Vector3.Cross(cl3, nc3);

            if (crossRes.y < 0)
            {
                Vector3 k = GetLinesIntersection(a, b, m, n);
                Vector3 l = GetLinesIntersection(c, d, o, p);

                Vector3 e = TestAB(d, l, -width, l);
                Vector3 r = TestAB(o, l, width, l);

                ST(k, P[i], "k");
                ST(l, P[i], "l");
                ST(e, P[i], "e");
                ST(r, P[i], "r");

                l_vertesx.Add(e);
                l_vertesx.Add(l);
                l_vertesx.Add(k);

                l_vertesx.Add(l);
                l_vertesx.Add(r);
                l_vertesx.Add(k);

                float ll = Vector3.Distance(lastL, l);
                float ek = Vector3.Distance(k, e);
                float kr = Vector3.Distance(k, r);

                l_uv.Add(new Vector2((uvi + ll) / Materials_Width, 0));//2 e
                l_uv.Add(new Vector2((uvi + ll) / Materials_Width, 1));//3 l
                l_uv.Add(new Vector2((uvi + ek + ll) / Materials_Width, 0));//4 k

                l_uv.Add(new Vector2((uvi + ek + ll + kr) / Materials_Width, 1));//5 l
                l_uv.Add(new Vector2((uvi + ek + ll + kr) / Materials_Width, 0));//6 r
                l_uv.Add(new Vector2((uvi + ek + ll) / Materials_Width, 0));//7 k

                uvi = uvi + (ek + ll + kr);
                lastL = l;
                lastR = r;
            }
            else
            {
                Vector3 k = GetLinesIntersection(c, d, o, p);
                Vector3 l = GetLinesIntersection(a, b, m, n);

                Vector3 e = TestAB(a, l, width, l);
                Vector3 r = TestAB(n, l, -width, l);

                ST(k, P[i], "k");
                ST(l, P[i], "l");
                ST(e, P[i], "e");
                ST(r, P[i], "r");

                l_vertesx.Add(l);
                l_vertesx.Add(e);
                l_vertesx.Add(k);

                l_vertesx.Add(r);
                l_vertesx.Add(l);
                l_vertesx.Add(k);


                float ll = Vector3.Distance(lastR, l);
                float ek = Vector3.Distance(k, e);
                float kr = Vector3.Distance(k, r);

                l_uv.Add(new Vector2((uvi + ll) / Materials_Width, 0));
                l_uv.Add(new Vector2((uvi + ll) / Materials_Width, 1));
                l_uv.Add(new Vector2((uvi + ek + ll) / Materials_Width, 1));


                l_uv.Add(new Vector2((uvi + ek + ll + kr) / Materials_Width, 1));
                l_uv.Add(new Vector2((uvi + ek + ll + kr) / Materials_Width, 0));
                l_uv.Add(new Vector2((uvi + ek + ll) / Materials_Width, 1));

                uvi = uvi + (ek + ll + kr);
                lastL = e;
                lastR = r;
            }
        }

        Vector3[] _opmn = GetABCD(trans[trans.Length - 2], trans[trans.Length - 1], width / 2);
        l_vertesx.Add(_opmn[2]);
        l_vertesx.Add(_opmn[1]);

        float lr = Vector3.Distance(l_vertesx[l_vertesx.Count - 2], lastL);

        l_uv.Add(new Vector2((uvi + lr) / Materials_Width, 1));
        l_uv.Add(new Vector2((uvi + lr) / Materials_Width, 0));
        #endregion

        #region triangles

        List<int> l_triangles = new List<int>();

        l_triangles.Add(0);
        l_triangles.Add(1);
        l_triangles.Add(3);

        l_triangles.Add(0);
        l_triangles.Add(3);
        l_triangles.Add(2);


        for (int i = 1; i < trans.Length - 1; i++)
        {
            l_triangles.Add(2 + (i - 1) * 6 + 0);//2
            l_triangles.Add(2 + (i - 1) * 6 + 1);//3
            l_triangles.Add(2 + (i - 1) * 6 + 2);//4

            l_triangles.Add(2 + (i - 1) * 6 + 3);//5
            l_triangles.Add(2 + (i - 1) * 6 + 4);//6
            l_triangles.Add(2 + (i - 1) * 6 + 5);//7

            if (i < trans.Length - 2)
            {
                l_triangles.Add(2 + (i - 1) * 6 + 3);//5
                l_triangles.Add(2 + (i) * 6 + 0);//8
                l_triangles.Add(2 + (i - 1) * 6 + 4);//6

                l_triangles.Add(2 + (i - 1) * 6 + 3);//5
                l_triangles.Add(2 + (i) * 6 + 1);//9
                l_triangles.Add(2 + (i) * 6 + 0);//8
            }
        }

        l_triangles.Add(l_vertesx.Count - 2);
        l_triangles.Add(l_vertesx.Count - 1);
        l_triangles.Add(l_vertesx.Count - 4);

        l_triangles.Add(l_vertesx.Count - 5);
        l_triangles.Add(l_vertesx.Count - 2);
        l_triangles.Add(l_vertesx.Count - 4);
        #endregion


        Vector3[] normals = new Vector3[l_vertesx.Count];
        for (int i = 0; i < normals.Length; i++)
        {
            normals[i] = Vector3.up;
        }

        Mesh mesh = new Mesh();
        mesh.vertices = l_vertesx.ToArray();
        mesh.triangles = l_triangles.ToArray();
        mesh.normals = normals;
        mesh.uv = l_uv.ToArray();
        return mesh;
    }

    private static Vector3[] GetABCD(Vector3 O1, Vector3 O2, float am)
    {
        Vector3 A = TestAB(O1, O2, -am, O1);
        Vector3 B = TestAB(O1, O2, -am, O2);
        Vector3 C = TestAB(O1, O2, am, O2);
        Vector3 D = TestAB(O1, O2, am, O1);

        Vector3[] abcd = new Vector3[] { A, B, C, D };
        return abcd;
    }

    #region 核心
    /// <summary>求平行线上的点</summary>
    /// <param name="m"></param>
    /// <param name="n"></param>
    /// <param name="am"></param>
    /// <param name="origin"></param>
    /// <returns></returns>
    private static Vector3 TestAB(Vector3 m, Vector3 n, float am, Vector3 origin)
    {
        float mn = Vector3.Distance(n, m);
        float mo = n.x - m.x;
        float no = n.z - m.z;
        float ox = origin.x;
        float oy = origin.z;

        float ap = am * mo / mn;
        float pm = am * no / mn;
        return new Vector3(ox - pm, 0, ap + oy);
    }
    /// <summary>求相交点</summary>
    /// <param name="o1"></param>
    /// <param name="o2"></param>
    /// <param name="o3"></param>
    /// <param name="o4"></param>
    private static Vector3 GetLinesIntersection(Vector3 o1, Vector3 o2, Vector3 o3, Vector3 o4)
    {
        float x1 = o1.x;
        float x2 = o2.x;
        float x3 = o3.x;
        float x4 = o4.x;

        float y1 = o1.y;
        float y2 = o2.y;
        float y3 = o3.y;
        float y4 = o4.y;

        float z1 = o1.z;
        float z2 = o2.z;
        float z3 = o3.z;
        float z4 = o4.z;

        float x = (x1 * (z2 - z1) * (x4 - x3) - x3 * (z4 - z3) * (x2 - x1) + (z3 - z1) * (x4 - x3) * (x2 - x1)) / ((z2 - z1) * (x4 - x3) - (z4 - z3) * (x2 - x1));
        float z = (z1 * (x2 - x1) * (z4 - z3) - z3 * (x4 - x3) * (z2 - z1) + (x3 - x1) * (z4 - z3) * (z2 - z1)) / ((x2 - x1) * (z4 - z3) - (x4 - x3) * (z2 - z1));


        return new Vector3(x, 0, z);
    }
    #endregion
    #endregion
    void ST(Vector3 p, Transform pre, string n)
    {
        GameObject i = Instantiate(temp);
        i.transform.position = p;
        i.transform.SetParent(pre.transform);
        i.name = n;
        i.SetActive(true);
    }
    public List<Transform> P = new List<Transform>();
    private void Update()
    {
        material.SetTextureOffset("_MainTex", new Vector2(Time.time * 0.5f, 0));
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机发出到点击坐标的射线
            RaycastHit hitInfo;
            if (Physics.Raycast(ray, out hitInfo))
            {
                GameObject game = new GameObject(transform.childCount + "");
                game.transform.SetParent(transform);
                game.transform.position = new Vector3(hitInfo.point.x, 0, hitInfo.point.z);
            }
        }
        if (Input.GetKeyDown(KeyCode.Space))
        {
            List<Vector3> Points = new List<Vector3>();
            for (int i = 0; i < transform.childCount; i++)
            {
                P.Add(transform.GetChild(i));
                Points.Add(transform.GetChild(i).position);
            }

            meshFilter.mesh = CreateRoad(Points.ToArray(), 4f);

        }

    }
}
